﻿using System;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Exusiai.Editor.Models;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Core.ECS;
using Core.ECS.Components;
using Core.Tools;
using Newtonsoft.Json.Linq;
using OpenTK.Mathematics;
using ReactiveUI;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Reactive;
using System.Windows.Input;
using System.Xml;
using System.Xml.Linq;

namespace Avalonia.Exusiai.Editor.ViewModels;

public class ObjectInspectionViewModel : INotifyPropertyChanged
{
    public static ObjectInspectionViewModel Instance;
    public static Actor? Actor;
    public static bool HaveSelectedItem { get; set; } = false;
    public event PropertyChangedEventHandler? PropertyChanged;
   
    public static void UpdateData(string name)
    {
        HaveSelectedItem = true;
        Actor = Actor.GetActor(name);
        if (Actor == null)
        {
            HaveSelectedItem = false;
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(HaveSelectedItem)));
            return;
        }
        Instance.PropertyChanged?.Invoke(null,
            new PropertyChangedEventArgs(nameof(HaveSelectedItem)));
        _name = name;
        Instance.PropertyChanged?.Invoke(null,
            new PropertyChangedEventArgs(nameof(Name)));
        Instance.PropertyChanged?.Invoke(null,
            new PropertyChangedEventArgs(nameof(Active)));
        Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(PositionX)));
        Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(PositionY)));
        Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(PositionZ)));
        Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(RotationX)));
        Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(RotationY)));
        Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(RotationZ)));
        Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(ScaleX)));
        Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(ScaleY)));
        Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(ScaleZ)));
        Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(ModelPath)));
        Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(MaterialPath)));
        BehaviorsTree.Clear();
        foreach(var behavior in Actor.BehaviorsName)
        {
            BehaviorsTree.Add(new BehaviorItemViewModel(){Name = behavior,IsEdit = false});
        }
    }
    public ObjectInspectionViewModel()
    {
        Instance = this;
        HaveSelectedItem = false;
        BehaviorsTree = new();
        AddBehaviorCommand = ReactiveCommand.Create(() =>
        {
            BehaviorsTree.Add(new BehaviorItemViewModel(){Name = "New Behavior",IsEdit = true});
            Actor.BehaviorsName.Add("New Behavior");
        });
        DeleteCommand =ReactiveCommand.Create<BehaviorItemViewModel>((item) =>
        {
            BehaviorsTree.Remove(item);
            Actor.BehaviorsName.Remove(item.Name);
        });
    }

    #region Behaviors
    public ICommand AddBehaviorCommand { get; set; }
    public ICommand DeleteCommand { get; set; }
    public static ObservableCollection<BehaviorItemViewModel> BehaviorsTree { get; set; }
    #endregion
    #region Transform
    public static float PositionX
    {
        get => Actor == null || Actor.Transform.LocalPosition.X == default ? 0 : Actor.Transform.LocalPosition.X;
        set
        {
            if (Actor == null)
            {
                return;
            }
            if (value == default) value = 0;
            if (value == Actor.Transform.LocalPosition.X) return;
            Actor.Transform.LocalPosition = new Vector3(value, Actor.Transform.LocalPosition.Y, Actor.Transform.LocalPosition.Z);
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(PositionX)));
            SerializeHelper.Serialize(Scene.Instance, GlobalData.Instance.SelectedFolder + "/scene.xml");
        }
    }
    public static float PositionY
    {
        get => Actor == null || Actor.Transform.LocalPosition.Y == default ? 0 : Actor.Transform.LocalPosition.Y;
        set
        {
            if (Actor == null)
            {
                return;
            }
            if (value == default) value = 0;
            if (value == Actor.Transform.LocalPosition.Y) return;
            Actor.Transform.LocalPosition = new Vector3(Actor.Transform.LocalPosition.X, value, Actor.Transform.LocalPosition.Z);
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(PositionY)));
            SerializeHelper.Serialize(Scene.Instance, GlobalData.Instance.SelectedFolder + "/scene.xml");
        }
    }
    public static float PositionZ
    {
        get => Actor == null || Actor.Transform.LocalPosition.Z == default ? 0 : Actor.Transform.LocalPosition.Z;
        set
        {
            if (Actor == null)
            {
                return;
            }
            if (value == default) value = 0;
            if (value == Actor.Transform.LocalPosition.Z) return;
            Actor.Transform.LocalPosition = new Vector3(Actor.Transform.LocalPosition.X, Actor.Transform.LocalPosition.Y, value);
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(PositionZ)));
            SerializeHelper.Serialize(Scene.Instance, GlobalData.Instance.SelectedFolder + "/scene.xml");
        }
    }
    public static float RotationX
    {
        get => Actor == null || Actor.Transform.LocalEulerAngle.X == default ? 0 : Actor.Transform.LocalEulerAngle.X;
        set
        {
            if (Actor == null)
            {
                return;
            }
            if (value == default) value = 0;
            if (value == Actor.Transform.LocalEulerAngle.X) return;
            Actor.Transform.LocalEulerAngle = new Vector3(value, Actor.Transform.LocalEulerAngle.Y, Actor.Transform.LocalEulerAngle.Z);
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(RotationX)));
            SerializeHelper.Serialize(Scene.Instance, GlobalData.Instance.SelectedFolder + "/scene.xml");
        }
    }
    public static float RotationY
    {
        get => Actor == null || Actor.Transform.LocalEulerAngle.Y == default ? 0 : Actor.Transform.LocalEulerAngle.Y;
        set
        {
            if (Actor == null)
            {
                return;
            }
            if (value == default) value = 0;
            if (value == Actor.Transform.LocalEulerAngle.Y) return;
            Actor.Transform.LocalEulerAngle = new Vector3(Actor.Transform.LocalEulerAngle.X, value, Actor.Transform.LocalEulerAngle.Z);
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(RotationY)));
            SerializeHelper.Serialize(Scene.Instance, GlobalData.Instance.SelectedFolder + "/scene.xml");
        }
    }
    public static float RotationZ
    {
        get => Actor == null || Actor.Transform.LocalEulerAngle.Z == default ? 0 : Actor.Transform.LocalEulerAngle.Z;
        set
        {
            if (Actor == null)
            {
                return;
            }
            if (value == default) value = 0;
            if (value == Actor.Transform.LocalEulerAngle.Z) return;
            Actor.Transform.LocalEulerAngle = new Vector3(Actor.Transform.LocalEulerAngle.X, Actor.Transform.LocalEulerAngle.Y, value);
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(RotationZ)));
            SerializeHelper.Serialize(Scene.Instance, GlobalData.Instance.SelectedFolder + "/scene.xml");
        }
    }
    public static float ScaleX
    {
        get => Actor == null || Actor.Transform.LocalScale.X == default ? 0 : Actor.Transform.LocalScale.X;
        set
        {
            if (Actor == null)
            {
                return;
            }
            if (value == default) value = 0;
            if (value == Actor.Transform.LocalScale.X) return;
            Actor.Transform.LocalScale = new Vector3(value, Actor.Transform.LocalScale.Y, Actor.Transform.LocalScale.Z);
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(ScaleX)));
            SerializeHelper.Serialize(Scene.Instance, GlobalData.Instance.SelectedFolder + "/scene.xml");
        }
    }
    public static float ScaleY
    {
        get => Actor == null || Actor.Transform.LocalScale.Y == default ? 0 : Actor.Transform.LocalScale.Y;
        set
        {
            if (Actor == null)
            {
                return;
            }
            if (value == default) value = 0;
            if (value == Actor.Transform.LocalScale.Y) return;
            Actor.Transform.LocalScale = new Vector3(Actor.Transform.LocalScale.X, value, Actor.Transform.LocalScale.Z);
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(ScaleY)));
            SerializeHelper.Serialize(Scene.Instance, GlobalData.Instance.SelectedFolder + "/scene.xml");
        }
    }
    public static float ScaleZ
    {
        get => Actor == null || Actor.Transform.LocalScale.Z == default ? 0 : Actor.Transform.LocalScale.Z;
        set
        {
            if (Actor == null)
            {
                return;
            }
            if (value == default) value = 0;
            if (value == Actor.Transform.LocalScale.Z) return;
            Actor.Transform.LocalScale = new Vector3(Actor.Transform.LocalScale.X, Actor.Transform.LocalScale.Y, value);
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(ScaleZ)));
            SerializeHelper.Serialize(Scene.Instance, GlobalData.Instance.SelectedFolder + "/scene.xml");
        }
    }
    #endregion
    #region Active
    public static bool Active
    {
        get =>Actor == null ? false : Actor.Active;
        set
        {
            if(Actor == null)
            {
                return;
            }
            if (value == Actor.Active) return;
            Actor.Active = value;
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(Active)));
            SerializeHelper.Serialize(Scene.Instance, GlobalData.Instance.SelectedFolder + "/scene.xml");
        }
    }
    private static bool _active = true;
    #endregion
    #region Name
    public static string? Name
    {
        get => _name;
        set
        {
            //if (_name == value) return;
            _name = value;
            UpdateText(value);
            Instance.PropertyChanged?.Invoke(null,
                new PropertyChangedEventArgs(nameof(Name)));
        }
    }
    private static string? _name = "";
    public ICommand UpdateTextCommand { get; set; }
    private static void UpdateText(string value)
    {
        if (Actor == null)
        {
            return;
        }
        if (value == null || value == "")
        {
            value = "Actor";
        }
        if (value == Actor.Name)
        {
            return;
        }
        Scene.Instance.ActorsByName.Remove(Actor.Name);
        if (Scene.Instance.ActorsByName.ContainsKey(value))
        {
            int n = 1;
            while (true)
            {
                if (Scene.Instance.ActorsByName.ContainsKey($"{value} ({n})"))
                {
                    n++;
                }
                else
                {
                    Actor.SetName($"{value} ({n})");
                    break;
                }
            }
        }
        else
        {
            Actor.SetName(value);
        }
        _name = Actor.Name;
        SceneHierarchyViewModel.UpdateSelectedItemName(_name);
        Scene.Instance.ActorsByName.Add(Actor.Name, Actor);
        SerializeHelper.Serialize(Scene.Instance, GlobalData.Instance.SelectedFolder + "/scene.xml");
    }
    #endregion
    #region Renderer
    public static string ModelPath
    {
        get => Actor == null || Actor.Renderer == null ? "" : Actor.Renderer.ModelPath;
        set
        {
            if (Actor == null) return;
            if (Actor.Renderer == null) return;
            Actor.Renderer.SetModelPath(value);
            Instance.PropertyChanged?.Invoke(null,
                    new PropertyChangedEventArgs(nameof(ModelPath)));
        }
    }
    public static string MaterialPath
    {
        get => Actor == null || Actor.Renderer == null ? "" : Actor.Renderer.MaterialPath;
        set
        {
            if (Actor == null) return;
            if (Actor.Renderer == null) return;
            Actor.Renderer.SetMaterialPath(value);
            Instance.PropertyChanged?.Invoke(null,
                    new PropertyChangedEventArgs(nameof(MaterialPath)));
        }
    }
    #endregion
}